from PySide6.QtCore import Qt, Signal, QPointF
from PySide6.QtGui import QKeyEvent
from serial.serialutil import SerialException

from ch9329 import CH9329
from conf import Config
from player import PlayThread
from recorder import Recorder
from video import Video

QT_MAPPING = {
    Qt.Key.Key_A: "a",
    Qt.Key.Key_B: "b",
    Qt.Key.Key_C: "c",
    Qt.Key.Key_D: "d",
    Qt.Key.Key_E: "e",
    Qt.Key.Key_F: "f",
    Qt.Key.Key_G: "g",
    Qt.Key.Key_H: "h",
    Qt.Key.Key_I: "i",
    Qt.Key.Key_J: "j",
    Qt.Key.Key_K: "k",
    Qt.Key.Key_L: "l",
    Qt.Key.Key_M: "m",
    Qt.Key.Key_N: "n",
    Qt.Key.Key_O: "o",
    Qt.Key.Key_P: "p",
    Qt.Key.Key_Q: "q",
    Qt.Key.Key_R: "r",
    Qt.Key.Key_S: "s",
    Qt.Key.Key_T: "t",
    Qt.Key.Key_U: "u",
    Qt.Key.Key_V: "v",
    Qt.Key.Key_W: "w",
    Qt.Key.Key_X: "x",
    Qt.Key.Key_Y: "y",
    Qt.Key.Key_Z: "z",
    Qt.Key.Key_1: "1",
    Qt.Key.Key_2: "2",
    Qt.Key.Key_3: "3",
    Qt.Key.Key_4: "4",
    Qt.Key.Key_5: "5",
    Qt.Key.Key_6: "6",
    Qt.Key.Key_7: "7",
    Qt.Key.Key_8: "8",
    Qt.Key.Key_9: "9",
    Qt.Key.Key_0: "0",

    Qt.Key.Key_Enter: "enter",
    Qt.Key.Key_Return: "enter",
    Qt.Key.Key_Escape: "escape",
    Qt.Key.Key_Backspace: "backspace",
    Qt.Key.Key_Tab: "tab",
    Qt.Key.Key_Space: "space",
    Qt.Key.Key_CapsLock: "caps_lock",
    Qt.Key.Key_NumLock: "num_lock",

    Qt.Key.Key_F1: "f1",
    Qt.Key.Key_F2: "f2",
    Qt.Key.Key_F3: "f3",
    Qt.Key.Key_F4: "f4",
    Qt.Key.Key_F5: "f5",
    Qt.Key.Key_F6: "f6",
    Qt.Key.Key_F7: "f7",
    Qt.Key.Key_F8: "f8",
    Qt.Key.Key_F9: "f9",
    Qt.Key.Key_F10: "f10",
    Qt.Key.Key_F11: "f11",
    Qt.Key.Key_F12: "f12",

    Qt.Key.Key_ScreenSaver: "print_screen",
    Qt.Key.Key_ScrollLock: "scroll_lock",
    Qt.Key.Key_Pause: "pause",
    Qt.Key.Key_Insert: "insert",
    Qt.Key.Key_Home: "home",
    Qt.Key.Key_PageUp: "page_up",
    Qt.Key.Key_Delete: "delete",
    Qt.Key.Key_End: "end",
    Qt.Key.Key_PageDown: "page_down",

    Qt.Key.Key_Right: "arrow_right",
    Qt.Key.Key_Left: "arrow_left",
    Qt.Key.Key_Down: "arrow_down",
    Qt.Key.Key_Up: "arrow_up",
    # symbols
    Qt.Key.Key_Minus: "-",
    Qt.Key.Key_Equal: "=",
    Qt.Key.Key_QuoteLeft: "`",
    Qt.Key.Key_BracketLeft: "[",
    Qt.Key.Key_BracketRight: "]",
    Qt.Key.Key_Backslash: "\\",
    Qt.Key.Key_Semicolon: ";",
    Qt.Key.Key_Apostrophe: "'",
    # Qt.Key.Key_Dead_Grave: "grave",
    Qt.Key.Key_Comma: ",",
    Qt.Key.Key_Period: ".",
    Qt.Key.Key_Slash: "/",
    Qt.Key.Key_AsciiTilde: "~",
    Qt.Key.Key_Exclam: "!",
    Qt.Key.Key_At: "@",
    Qt.Key.Key_NumberSign: "#",
    Qt.Key.Key_Dollar: "$",
    Qt.Key.Key_Percent: "%",
    Qt.Key.Key_AsciiCircum: "^",
    Qt.Key.Key_Ampersand: "&",
    Qt.Key.Key_Asterisk: "*",
    Qt.Key.Key_ParenLeft: "(",
    Qt.Key.Key_ParenRight: ")",
    Qt.Key.Key_Underscore: "_",
    Qt.Key.Key_Plus: "+",
    Qt.Key.Key_BraceLeft: "{",
    Qt.Key.Key_BraceRight: "}",
    Qt.Key.Key_Bar: "|",
    Qt.Key.Key_Colon: ":",
    Qt.Key.Key_QuoteDbl: '"',
    Qt.Key.Key_Less: "<",
    Qt.Key.Key_Greater: ">",
    Qt.Key.Key_Question: "?",
}


class Kvm(Video):
    toolbar_signal = Signal(Qt.Key)

    def __init__(self, conf: Config):
        super().__init__(conf)
        self.conf = conf
        # 初始化串口键盘
        self.ch9329 = self.open_serial()
        self.recorder = Recorder()

    def open_serial(self):
        try:
            return CH9329(
                self.conf.ser.port,
                self.conf.ser.rate,
                timeout=self.conf.ser.timeout,
                screenx=self.conf.screen.width,
                screeny=self.conf.screen.height
            )
        except SerialException as ex:
            print(ex.strerror)
        return None

    """
        鼠标移动到绝对位置
    """
    def absolute_move(self, event):
        pos = event.position().toPoint()

        pixmap_width = self.video_size().width()
        pixmap_height = self.video_size().height()

        # 计算图像在Label上的位置偏移，按比例显示的时候，Label下方空白，鼠标位置偏移
        x_offset = int((self.width() - pixmap_width) / 2)
        x = pos.x() - x_offset if pos.x() - x_offset > 0 else 0
        x = pixmap_width if x > pixmap_width else x

        y_offset = int((self.height() - pixmap_height) / 2)
        y = pos.y() - y_offset if pos.y() - y_offset > 0 else 0
        y = pixmap_height if y > pixmap_height else y

        # 计算屏幕分辨率和图像的比例
        scale_x = self.conf.screen.width / pixmap_width
        scale_y = self.conf.screen.height / pixmap_height

        x = int(x * scale_x)
        y = int(y * scale_y)
        x = x-1 if x >= pixmap_width else x
        y = y-1 if y >= pixmap_height else y
        # 按比例放大串口发送的位置
        if self.ch9329 is None:
            self.ch9329 = self.open_serial()
        if self.ch9329 is not None:
            self.ch9329.mouse.absolute_move(x, y)
        if self.recorder.is_started():
            self.recorder.mouse_absolute_move(event.x(), event.y())

    """
        鼠标按键按下（只有左右键，忽略中键及其他）
    """
    def mouse_press(self, event):
        button = "left" if event.button() == Qt.MouseButton.LeftButton else "right"
        if self.ch9329 is None:
            self.ch9329 = self.open_serial()
        if self.ch9329 is not None:
            self.ch9329.mouse.press(button)
        if self.recorder.is_started():
            self.recorder.mouse_press(button)

    """
        鼠标移动
    """
    def mouseMoveEvent(self, event):
        try:
            self.absolute_move(event)
        except SerialException as ex:
            print(ex.strerror)

    """
        鼠标单击
    """
    def mousePressEvent(self, event):
        try:
            self.absolute_move(event)
            self.mouse_press(event)
        except SerialException as ex:
            print(ex.strerror)

    """
            鼠标双击
    """
    def mouseDoubleClickEvent(self, event):
        try:
            self.absolute_move(event)
            self.mouse_press(event)
            self.mouse_press(event)
        except SerialException as ex:
            print(ex.strerror)
    """
        鼠标按键弹起
    """
    def mouseReleaseEvent(self, event):
        try:
            if self.ch9329 is None:
                self.ch9329 = self.open_serial()
            if self.ch9329 is not None:
                self.ch9329.mouse.release()
        except SerialException as ex:
            print(ex.strerror)
        if self.recorder.is_started():
            self.recorder.mouse_release()

    """
        鼠标滚轮（没有左右滚轮）
    """
    def wheelEvent(self, event):
        y = event.angleDelta().y()
        y = 1 if y > 0 else -1
        try:
            if self.ch9329 is not None:
                self.ch9329 = self.open_serial()
            if self.ch9329 is not None:
                self.ch9329.mouse.wheel(y)
        except SerialException as ex:
            print(ex.strerror)
        if self.recorder.is_started():
            self.recorder.mouse_wheel(y)

    """
        键盘按下事件
    """
    def keyPressEvent(self, event: QKeyEvent):
        key = Qt.Key(event.key())
        if key in QT_MAPPING:
            # 键值转换（单按控制键会被忽略）
            text = QT_MAPPING[Qt.Key(event.key())]
            # 读取控制键
            mods = event.modifiers()

            if mods == Qt.KeyboardModifier.ControlModifier and (
                    key == Qt.Key.Key_F11
                    or key == Qt.Key.Key_F1
                    or key == Qt.Key.Key_F2
                    or key == Qt.Key.Key_F3
                    or key == Qt.Key.Key_F4):
                self.toolbar_signal.emit(key)
                return

            modifiers = []
            if Qt.KeyboardModifier.MetaModifier in mods:
                modifiers.append("win")
            if Qt.KeyboardModifier.ControlModifier in mods:
                modifiers.append("ctrl")
            if Qt.KeyboardModifier.ShiftModifier in mods:
                modifiers.append("shift")
            if Qt.KeyboardModifier.AltModifier in mods:
                modifiers.append("alt")
            try:
                if self.ch9329 is not None:
                    self.ch9329 = self.open_serial()
                if self.ch9329 is not None:
                    self.ch9329.keyboard.press(text, modifiers=modifiers)
            except SerialException as ex:
                print(ex.strerror)
            if self.recorder.is_started():
                self.recorder.keyboard_press(text, modifiers)

    """
        键盘弹起事件
    """
    def keyReleaseEvent(self, event: QKeyEvent):
        try:
            if self.ch9329 is not None:
                self.ch9329 = self.open_serial()
            if self.ch9329 is not None:
                self.ch9329.keyboard.release()
        except SerialException as ex:
            print(ex.strerror)
        if self.recorder.is_started():
            self.recorder.keyboard_release()

    def closeEvent(self, event):
        if self.ch9329 is not None:
            self.ch9329.close()
        super().closeEvent(event)
